<template>
  <div class="graph-list">
    <div class="canvas-box">
      <DragLeftBar :startDrag="startDrag"/>
      <div id="canvasContainer" class="canvas-container"></div>
    </div>
    <TeleportContainer/>
  </div>
</template>

<script setup lang="ts" name="GraphList">
import DragLeftBar from './drag-left-bar/drag-left-bar.vue';
import {onMounted, ref} from 'vue';
import {
  edgeOption,
  graphOption,
  HighlightingConfig, NODE_MAP_OPTION, NODES_MAP,
  PORT_ENUM,
  registerNode,
  ValidateConnection
} from '@/view/graph/model/nodes';
import {getTeleport} from '@antv/x6-vue-shape';
import {Graph, NodeView} from '@antv/x6';
import {NodeConfig, NodeSizeItem, NodeTypeEnum} from '@/view/graph/model/type';
import {ElMessage} from 'element-plus';
import {GenerationNodeData, ValidateMagnetRules} from '@/view/graph/methods/methods';
import {Clipboard} from '@antv/x6-plugin-clipboard';
import {eventMap} from '@/view/graph/methods/event';
import {cloneDeep, isEmpty} from 'lodash';
import {parseObj2Arr} from '@/utils/parseObj2Arr';
import {storeToRefs} from 'pinia';
import {workFlowStoreCounter} from '@/store/work-flow';


let graph: Graph;
const TeleportContainer = getTeleport();

const workFlowStore = workFlowStoreCounter();
const {nodeActiveStatusObject} = storeToRefs(workFlowStore);

const x = ref(0);
const y = ref(0);

const childrenX = ref(0);
const childrenY = ref(0);

onMounted(() => {
  init();
});


/**
 * 边删除按钮
 * @param cell
 * @param view
 */
const newEdgeMouseEnter = ({cell, view}: { cell: any; view: NodeView }) => {
  // 新的事件处理程序逻辑
  const {graph} = view;
  const node = graph.getCellById(cell.source.cell);
  const targetNode = graph.getCellById(cell.target.cell);

  if (
      !(node.shape === NodeTypeEnum.ITERATION && targetNode.shape === NodeTypeEnum.ITERATION_BODY)
  ) {
    cell.addTools([
      {
        name: 'button-remove',
        args: {distance: -20}
      }
    ]);
  }
};

/**
 * 初始化节点
 */
function initGraphNode() {
  graph?.addNode({
    shape: NODES_MAP.START,
    label: '开始',
    x: 200,
    y: 300,
    ports: {
      items: NODE_MAP_OPTION[NODES_MAP.START]?.port
    },
    data: {
      ...GenerationNodeData({code: NODES_MAP.START, name: '开始'})
    }
  });

  graph?.addNode({
    shape: NODES_MAP.END,
    label: '结束',
    x: 700,
    y: 300,
    ports: {
      items: NODE_MAP_OPTION[NODES_MAP.END]?.port
    },
    data: {
      ...GenerationNodeData({code: NODES_MAP.END, name: '结束'})
    }
  });
}

/**
 * 初始化
 */
async function init() {
  // 注册节点
  registerNode();
  // 注册画布
  graph = new Graph({
    container: document.getElementById('canvasContainer') || undefined,
    ...graphOption,
    highlighting: HighlightingConfig,
    connecting: {
      highlight: true,
      snap: {
        radius: 50
      },
      allowMulti: 'withPort',
      allowLoop: false,
      createEdge() {
        return graph?.createEdge(edgeOption);
      },
      validateEdge({
                     edge
                   }: {
        edge: {
          source: { port: string; cell: string };
          target: { port: string; cell: string };
          setLabels: any;
          setData: any;
          attr: any;
        };
      }) {
        if (!graph) {
          return;
        }
        if (edge.source.port && edge.target.port === PORT_ENUM.INPUT) {
          const {source} = edge;
          const sourceNode = graph?.getCellById(source.cell);
          if (sourceNode.shape === NodeTypeEnum.QUESTION_CLASS) {
            edge?.setData(
                {
                  type: NodeTypeEnum.QUESTION_CLASS,
                  categoryId: source.port,
                  lastModify: new Date()
                },
                {overwrite: true}
            );
          }
          if (sourceNode.shape === NodeTypeEnum.CONDITIONAL_BRANCH) {
            edge?.setData(
                {
                  type: NodeTypeEnum.CONDITIONAL_BRANCH,
                  case_id: source.port,
                  lastModify: new Date()
                },
                {overwrite: true}
            );
          }
          if (sourceNode.shape === NodeTypeEnum.QA) {
            edge?.setData(
                {
                  type: NodeTypeEnum.QA,
                  option_id: source.port,
                  lastModify: new Date()
                },
                {overwrite: true}
            );
          }
          return true;
        }
        ElMessage.error('不合法连线');
        return false;

      },
      validateMagnet({cell, magnet}) {
        if (
            magnet.getAttribute('port-group') === 'left' &&
            cell.shape === NodeTypeEnum.ITERATION_BODY
        ) {
          return true;
        }
        if (magnet.getAttribute('port-group') !== 'right') {
          return false;
        }
        // 连线可行性校验
        const {result, msg} = ValidateMagnetRules(graph as Graph, cell);
        if (!result) {
          ElMessage.error(msg);
          return false;
        }
        return true;
      },
      validateConnection({sourceCell, targetCell, sourceMagnet, targetMagnet}) {
        return ValidateConnection(sourceCell, targetCell, sourceMagnet, targetMagnet);
      }
    }
  });
  graph.use(
      new Clipboard({
        enabled: true
      })
  );
  const newEventMap = cloneDeep(eventMap);
  newEventMap['edge:mouseenter'] = newEdgeMouseEnter;

  graph.on('node:click', ({ node }: { node: any }) => {
    nodeActiveStatusObject.value = {};
    nodeActiveStatusObject.value[node.id] = true;
  });

  // 绑定静态事件
  parseObj2Arr(newEventMap).map(item => {
    if (!graph) {
      return;
    }
    graph.on(item.key, item.value);
  });
  initGraphNode();
}

/**
 * 点击节点
 */
const startDrag = (nodeItem: NodeConfig) => {
  if (!graph || [NODES_MAP.START].includes(nodeItem.code as NODES_MAP)) {
    return;
  }
  const cell = graph.getCellById(Object.keys(nodeActiveStatusObject.value)[0]);
  if ([NodeTypeEnum.ITERATION, NodeTypeEnum.ITERATION_BODY].includes(cell?.shape)) {
    if (
        [NodeTypeEnum.ITERATION, NodeTypeEnum.ITERATION_BODY].includes(cell?.shape) &&
        [NodeTypeEnum.ITERATION, NodeTypeEnum.QA].includes(nodeItem.code as NODES_MAP)
    ) {
      ElMessage.error('不支持嵌套问答/批量节点');
      return;
    }
  }
  x.value += 40;
  y.value += 20;
  const nodeList = graph
      ?.getNodes()
      ?.filter(item => item.shape === nodeItem.code)
      ?.map(item => item.getData().title);
  let name = cloneDeep(nodeItem.name);
  if (!isEmpty(nodeList)) {
    let index = 1;
    let newModelName = `${name}${index}`;
    // 查找不重复的名称
    while (nodeList.includes(newModelName)) {
      index++;
      newModelName = `${name}${index}`;
    }
    name = newModelName;
  }
  const newNodeItem = cloneDeep(nodeItem);
  newNodeItem.name = name;
  const translateXY: any = graph.translate();
  const graphToLocalXY = graph.graphToLocal(translateXY);
  const node = graph?.addNode({
    shape: nodeItem.code,
    label: nodeItem.name,
    x: graphToLocalXY.x + x.value,
    y: graphToLocalXY.y + y.value,
    width: NodeSizeItem[nodeItem.code] ? NodeSizeItem[nodeItem.code].width : 588,
    height: NodeSizeItem[nodeItem.code] ? NodeSizeItem[nodeItem.code].height : 588,
    ports: {
      items: NODE_MAP_OPTION[nodeItem.code as NODES_MAP]?.port
    },
    data: {
      ...GenerationNodeData(newNodeItem),
      isClick: true
    }
  });
  if (node?.shape === NodeTypeEnum.QUESTION_CLASS) {
    node.removePortAt(0);
    node.addPort({
      id: node.data.category[0].id,
      group: 'right',
      args: {
        y: 500,
        x: '100%'
      }
    });
    node.addPort({
      id: node.data.category[1].id,
      group: 'right',
      args: {
        y: 520,
        x: '100%'
      }
    });
  }
  if (node?.shape === NodeTypeEnum.CONDITIONAL_BRANCH) {
    node.removePortAt(0);
    node.addPort({
      id: node.data.case[0].case_id,
      group: 'right',
      args: {
        y: 180,
        x: '100%'
      }
    });
    node.addPort({
      id: node.data.case[1].case_id,
      group: 'right',
      args: {
        y: 310,
        x: '100%'
      }
    });
  }
  if (node?.shape === NodeTypeEnum.ITERATION) {
    const {x, y} = node.position();
    const parent = graph.addNode({
      shape: NodeTypeEnum.ITERATION_BODY,
      x: x,
      y: y + 454 + 60,
      ports: {
        items: NODE_MAP_OPTION[NodeTypeEnum.ITERATION_BODY as NODES_MAP]?.port
      },
      data: {
        ...GenerationNodeData({
          ...newNodeItem,
          code: NodeTypeEnum.ITERATION_BODY,
          name: '批处理体',
          iteration_node_id: node.id
        }),
        isClick: true
      }
    });
    graph.addEdge({
      source: {
        cell: node,
        port: PORT_ENUM.BOTTOM_INPUT
      },
      target: {
        cell: parent,
        port: PORT_ENUM.TOP_OUTPUT
      },
      attrs: edgeOption.attrs,
      router: edgeOption.router,
      connector: edgeOption.connector
    });
  }

  if (NodeTypeEnum.ITERATION === cell?.shape) {
    const outNode = graph.getNeighbors(cell, {incoming: false, outgoing: true})?.[0] as any;
    outNode.addChild(node);
    childrenX.value += 40;
    childrenY.value += 40;
    node.position(childrenX.value, childrenY.value, {relative: true});
  } else if (NodeTypeEnum.ITERATION_BODY === cell?.shape) {
    childrenX.value += 40;
    childrenY.value += 40;
    cell.addChild(node);
    node.position(childrenX.value, childrenY.value, {relative: true});
  }
};
</script>

<style scoped lang="scss">
.graph-list {
  height: 100%;
}

.canvas-box {
  height: calc(100% - 64px);
  display: flex;

  .canvas-container {
    flex: 1;
  }
}
</style>
